import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => MyAppState(),
      child: MaterialApp(
        title: 'Namer App',
        theme: ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
        ),
        home: MyHomePage(),
      ),
    );
  }
}

/// 定义应用运行所需的数据。现在，其中仅包含一个变量，即通过随机函数生成当前的随机单词对。您稍后将在其中添加代码。
///
/// 类似ViewModel
class MyAppState extends ChangeNotifier {
  var current = WordPair.random();

  /// getNext() 方法为 current 重新分配了新的随机 WordPair。
  ///
  /// 它还调用 notifyListeners() (ChangeNotifier) 的一个方法），以确保向任何通过 watch 方法跟踪 MyAppState 的对象发出通知。
  void getNext() {
    current = WordPair.random();
    notifyListeners();
  }

  /// 此属性使用一个空的列表进行初始化，即 []。
  /// 使用 generics 指定该列表只能包含单词对：<WordPair>[]。
  /// 这有助于增强应用的可靠性 — 如果您尝试向应用添加 WordPair 以外的任何内容，Dart 甚至会拒绝运行应用。
  /// 相应的，您可以使用 favorites 列表，同时知道其中永远不会隐藏任何不需要的对象（如 null）。
  var favorites = <WordPair>[];

  /// 从收藏夹列表中删除当前单词对（如果已经存在），或者添加单词对（如果不存在）。
  /// 在任何一种情况下，代码都会在之后调用 notifyListeners();。
  void toggleFavorite() {
    if (favorites.contains(current)) {
      favorites.remove(current);
    } else {
      favorites.add(current);
    }
    notifyListeners();
  }
}

/// 转换为有状态widget
class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var selectedIndex = 0;
  @override
  Widget build(BuildContext context) {
    // 根据选中修改右边的page
    Widget page;
    switch (selectedIndex) {
      case 0:
        page = GeneratorPage();
        break;
      case 1:
        page = FavoritesPage();
        break;
      default:
        throw UnimplementedError('no widget for $selectedIndex');
    }

    return LayoutBuilder(
      builder: (context, constraints) {
        return Scaffold(
          body: Row(
            children: [
              SafeArea(
                child: NavigationRail(
                  extended: constraints.maxWidth >= 600,//横像素大于600自动展开
                  destinations: [
                    NavigationRailDestination(
                      icon: Icon(Icons.home),
                      label: Text('Home'),
                    ),
                    NavigationRailDestination(
                      icon: Icon(Icons.favorite),
                      label: Text('Favorites'),
                    ),
                  ],
                  selectedIndex: selectedIndex,
                  onDestinationSelected: (value) {
                    print('selected: $value');
                    setState(() {
                      selectedIndex = value;
                    });
                  },
                ),
              ),
              Expanded(
                child: Container(
                  color: Theme.of(context).colorScheme.primaryContainer,
                  child: page,
                ),
              ),
            ],
          ),
        );
      }
    );
  }
}

class GeneratorPage extends StatelessWidget {
  /// 每个 widget 均定义了一个 build() 方法，每当 widget 的环境发生变化时，系统都会自动调用该方法，以便 widget 始终保持最新状态。
  @override
  Widget build(BuildContext context) {
    // MyHomePage 使用 watch 方法跟踪对应用当前状态的更改。
    var appState = context.watch<MyAppState>();
    var pair = appState.current;

    // 点赞按钮
    IconData icon;
    if (appState.favorites.contains(pair)) {
      icon = Icons.favorite;
    } else {
      icon = Icons.favorite_border;
    }

    // 每个 build 方法都必须返回一个 widget 或（更常见的）嵌套 widget 树。
    // 在本例中，顶层 widget 是 Scaffold。
    // 您不会在此 Codelab 中使用 Scaffold，但它是一个有用的 widget。
    // 在绝大多数真实的 Flutter 应用中都可以找到该 widget。
    return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('A random AWESOME idea:'),
            // 第二个 Text widget 接受 appState，并访问该类的唯一成员 current（这是一个 WordPair）。
            // WordPair 提供了一些有用的 getter，例如 asPascalCase 或 asSnakeCase。此处，我们使用了 asLowerCase。
            // 但如果您希望选择其他选项，您现在可以对其进行更改。
            BigCard(pair: pair),
            SizedBox(height: 10),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                ElevatedButton.icon(
                  onPressed: () {
                    appState.toggleFavorite();
                  },
                  icon: Icon(icon),
                  label: Text('Like'),
                ),
                SizedBox(width: 10),
                ElevatedButton(
                    onPressed: () {
                      appState.getNext();
                      print('button pressed!');
                    },
                    child: Text('Next')),
              ],
            ),
            // 请注意，Flutter 代码大量使用了尾随逗号。
            // 此处并不需要这种特殊的逗号，因为 children 是此特定 Column 参数列表的最后一个（也是唯一一个）成员。
            // 不过，在一般情况下，使用尾随逗号是一种不错的选择。
            // 尾随逗号可大幅减小添加更多成员的必要性，并且还可以在 Dart 的自动格式化程序中作为添加换行符的提示。
            // 如需了解详细信息，请参阅代码格式。
          ],
        ),
      );
  }
}

/// 使用过的快捷操作
///
/// 1.Extract Widget
///
/// 2.Wrap with Padding
///
/// 3.Wrap with widget->Card
class BigCard extends StatelessWidget {
  const BigCard({
    super.key,
    required this.pair,
  });

  final WordPair pair;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);

    /// 通过使用 theme.textTheme,，您可以访问应用的字体主题。此类包括以下成员：bodyMedium（针对中等大小的标准文本）、caption（针对图片的说明）或 headlineLarge（针对大标题）。
    /// displayMedium 属性是专用于“展示文本”的大号样式。此处的“展示”一词用于反映版式效果，例如展示字体。displayMedium 的文档指出“展示样式保留用于简短、重要的文本”— 这正是我们的应用场景。
    /// 从理论上说，主题的 displayMedium 属性可以是 null。Dart（您编写此应用所使用的编程语言）采用 null 安全机制，因此不会允许您调用值可能为 null 的对象的方法。不过，在这种情况下，您可以使用 ! 运算符（“bang 运算符”）向 Dart 保证您知道自己在做什么。(在本例中，displayMedium 肯定不是 null。不过，判断这一点的方法超出了此 Codelab 的讨论范围。）
    /// 调用 displayMedium 上的 copyWith() 会返回文本样式的副本，以及您定义的更改。在本例中，您只是更改文本的颜色。
    /// 若要获取新颜色，您需要再次访问应用的主题。配色方案的 onPrimary 属性定义了一种非常适合在应用的 primary 颜色上使用的颜色。
    final style = theme.textTheme.displayMedium!.copyWith(
      color: theme.colorScheme.onPrimary,
    );
    return Card(
      color: theme.colorScheme.primary,
      child: Padding(
        padding: const EdgeInsets.all(20),
        child: Text(
          pair.asLowerCase,
          style: style,
          semanticsLabel: "${pair.first} ${pair.second}",
        ),
      ),
    );
  }
}

class FavoritesPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();

    if (appState.favorites.isEmpty) {
      return Center(
        child: Text('No favorites yet.'),
      );
    }

    return ListView(
      children: [
        Padding(
          padding: const EdgeInsets.all(20),
          child: Text('You have '
              '${appState.favorites.length} favorites:'),
        ),
        for (var pair in appState.favorites)
          ListTile(
            leading: Icon(Icons.favorite),
            title: Text(pair.asLowerCase),
          ),
      ],
    );
  }
}
